home *** CD-ROM | disk | FTP | other *** search
- #ifndef VARRAY_H
- #define VARRAY_H
-
- // This is a template for a virtual array of type T.
-
- #include <stdio.h>
- #include <dos.h>
-
- #ifndef TRUE
- #define TRUE -1
- #endif
- #ifndef FALSE
- #define FALSE 0
- #endif
-
- template <class T>
- class varray
- {
- private:
- int expanded_memory_allocated(void);
- // Allocated expanded memory. If this can't be done,
- // an attempt will be made to use a disk instead.
- unsigned int expanded_memory_handle;
- int free_expanded_memory;
- int free_disk_memory;
- // The temporary file used for virtual memory needs to be
- // freed.
- void free_memory(void);
- // Free real memory used for pages, etc.
- int free_real_memory;
- // Real memory needs to be freed.
- int map_expanded_memory(int physical_page,long logical_page);
- // Associate a physical page in the physical page frame
- // with a logical page of expanded memory.
- int memory_allocated(void);
- // Allocate real memory for pages, etc.
- long num_elements_in_array;
- // Number of elements in the array.
- unsigned int num_elements_per_page;
- // Number of array elements in a page.
- int num_real_pages;
- // Number of pages kept in real memory.
- char *page_frame_ptr;
- // Pointer to expanded memory physical frame.
- T **real_page;
- // A page in real memory.
- long *starting_element_num;
- // Index of first array element in page in real memory.
- FILE *vm;
- // Temporary file used for virtual memory.
- long *vm_access;
- // "When" a page in real memory was last accessed.
- long vm_access_num;
- // Current "time".
- public:
- int allocated(void) {return (free_real_memory &&
- (free_expanded_memory || free_disk_memory));}
-
- varray(T& initialized_element,long element_count,
- int real_page_count=4,unsigned int page_size=32768);
- // Construct a virtual array of type T. The arguments are as follow:
- //
- // initialized_element -- an initialized element of type T.
- //
- // element_count -- the number of elements in the array.
- //
- // real_page_count -- the number of pages to be kept in memory.
- // This should be at least as large as the maximum number of elements
- // of the array referenced at once. Small values result in too much
- // paging; large values result in too much overhead searching for the
- // page containing an element.
- //
- // page_size -- the number of bytes in a page. This must be at least
- // sizeof(T). This is used only when a disk is used for virtual memory.
- // (When expanded memory is used, the page size is effectively 32K.) 32K
- // is probably optimal due to the overhead of searching for a page.
-
- ~varray(void);
- // If expanded memory was used, free it. If a temporary file was used,
- // close (and so delete) it. If real memory was allocated, free it.
-
- T *vm_ptr(long element_num);
- // Return a pointer to an element of the array. When T is a structure, it
- // is faster to use this pointer than to overload [] and search virtual memory
- // for each component of the structure.
-
- T& operator[](long element_num) {return *vm_ptr(element_num);}
- // Return an element of the array by overloading [].
- };
-
- template <class T>
- varray<T>::varray(T& initialized_element,long element_count,int real_page_count,
- unsigned int page_size)
- // Construct a virtual array of type T. The arguments are as follow:
- //
- // initialized_element -- an initialized element of type T.
- //
- // element_count -- the number of elements in the array.
- //
- // real_page_count -- the number of pages to be kept in memory.
- // This should be at least as large as the maximum number of elements
- // of the array referenced at once. Small values result in too much
- // paging; large values result in too much overhead searching for the
- // page containing an element.
- //
- // page_size -- the number of bytes in a page. This must be at least
- // sizeof(T). This is used only when a disk is used for virtual memory.
- // (When expanded memory is used, the page size is effectively 32K.) 32K
- // is probably optimal due to the overhead of searching for a page.
- {
- unsigned int element_index;
- long element_num;
-
- free_real_memory=FALSE;
- free_disk_memory=FALSE;
- free_expanded_memory=FALSE;
- num_real_pages=real_page_count;
- num_elements_in_array=element_count;
- if (sizeof(T) <= 32768)
- {
- num_elements_per_page=32768/sizeof(T);
- free_expanded_memory=expanded_memory_allocated();
- }
- if (free_expanded_memory)
- if (memory_allocated()) // Allocate space for the active pages.
- {
- free_real_memory=TRUE;
- long expanded_memory_page_num=0L;
- int real_page_num=0;
- vm_access_num=0;
- int successful=TRUE;
- for (element_num=(long) 0;
- ((successful) && (element_num < num_elements_in_array));
- element_num+=((long) num_elements_per_page))
- {
- if (real_page_num < real_page_count)
- // Initialize real page.
- {
- vm_access_num++;
- for (element_index=(unsigned int) 0;
- element_index < num_elements_per_page;
- element_index++)
- real_page[real_page_num][element_index]
- =initialized_element;
- vm_access[real_page_num]=vm_access_num;
- starting_element_num[real_page_num]=element_num;
- real_page_num++;
- }
- // Initialize virtual page.
- if (successful=map_expanded_memory(0,expanded_memory_page_num++))
- {
- if (successful
- =map_expanded_memory(1,expanded_memory_page_num++))
- memcpy((void *) page_frame_ptr,(void *) &(real_page[0][0]),
- num_elements_per_page*sizeof(T));
- }
- }
- if (! successful)
- cerr
- << "Fatal error: there is an unexpected problem with expanded "
- << "memory." << '\n';
- }
- else
- cerr << "Fatal error: not enough real memory for virtual array."
- << '\n';
- else
- {
- num_elements_per_page=page_size/sizeof(T);
- if ((vm=tmpfile()) == NULL) // Get a file for the virtual memory.
- cerr << "Fatal error: cannot open virtual memory." << '\n';
- else
- if (memory_allocated()) // Allocate space for the active pages.
- {
- free_real_memory=TRUE;
- free_disk_memory=TRUE;
- int real_page_num=0;
- vm_access_num=0;
- int successful=TRUE;
- for (element_num=(long) 0;
- ((successful) && (element_num < num_elements_in_array));
- element_num+=((long) num_elements_per_page))
- {
- if (real_page_num < real_page_count)
- // Initialize real page.
- {
- vm_access_num++;
- for (element_index=(unsigned int) 0;
- element_index < num_elements_per_page;
- element_index++)
- real_page[real_page_num][element_index]
- =initialized_element;
- vm_access[real_page_num]=vm_access_num;
- starting_element_num[real_page_num]=element_num;
- real_page_num++;
- }
- // Initialize virtual page.
- successful=(fwrite(&(real_page[0][0]),
- sizeof(T),num_elements_per_page,vm)
- == num_elements_per_page);
- }
- if (! successful)
- cerr
- << "Fatal error: not enough disk space for virtual array."
- << '\n';
- }
- else
- cerr << "Fatal error: not enough real memory for virtual array."
- << '\n';
- }
- }
-
- template <class T>
- varray<T>::~varray()
- // If expanded memory was used, free it. If a temporary file was used,
- // close (and so delete) it. If real memory was allocated, free it.
- {
- if (free_expanded_memory)
- {
- union REGS input_reg;
- union REGS output_reg;
-
- input_reg.h.ah=0x45;
- input_reg.x.dx=expanded_memory_handle;
- int86(0x67,&input_reg,&output_reg);
- }
- if (free_disk_memory)
- fclose(vm);
- if (free_real_memory)
- free_memory();
- };
-
- template <class T>
- int varray<T>::expanded_memory_allocated()
- {
- char *EMM_device_name = "EMMXXXX0";
- union REGS input_reg;
- union
- {
- unsigned long device_name_address;
- char *device_name_ptr;
- };
- union REGS output_reg;
- union
- {
- unsigned long pf_address;
- char *pf_ptr;
- };
- long pages_needed;
- int result;
- struct SREGS segment_reg;
-
- typedef T *t_ptr;
-
- result=FALSE;
- pages_needed=num_elements_in_array/long(num_elements_per_page);
- if (pages_needed*long(num_elements_per_page) < num_elements_in_array)
- pages_needed++;
- pages_needed+=pages_needed; // VARRAY uses 32K byte pages;
- // expanded memory uses 16K byte pages.
- if (pages_needed <= 0xffff)
- {
- input_reg.h.ah=0x35;
- input_reg.h.al=0x67;
- intdosx(&input_reg,&output_reg,&segment_reg);
- device_name_address=(((unsigned long) (segment_reg.es)) << 16) + 10L;
- if (memcmp(EMM_device_name,device_name_ptr,8) == 0)
- {
- input_reg.h.ah=0x42;
- int86(0x67,&input_reg,&output_reg);
- if ((output_reg.h.ah == 0)
- && (pages_needed <= long(output_reg.x.bx)))
- {
- input_reg.h.ah=0x43;
- input_reg.x.bx=(unsigned int) pages_needed;
- int86(0x67,&input_reg,&output_reg);
- expanded_memory_handle=output_reg.x.dx;
- if (output_reg.h.ah == 0)
- {
- input_reg.h.ah=0x41;
- int86(0x67,&input_reg,&output_reg);
- if (result=(output_reg.h.ah == 0))
- {
- pf_address=(((unsigned long) (output_reg.x.bx)) << 16);
- page_frame_ptr=pf_ptr;
- }
- }
- }
- }
- }
- return result;
- }
-
- template <class T>
- int varray<T>::memory_allocated()
- // Allocate real memory for pages, etc.
- {
- int result;
- int real_page_num;
-
- typedef T *t_ptr;
-
- if (result=((vm_access=new long[num_real_pages]) != NULL))
- {
- if (result=((starting_element_num=new long[num_real_pages]) != NULL))
- if (result=((real_page=new t_ptr[num_real_pages]) != NULL))
- {
- for (real_page_num=0;
- ((result) && (real_page_num < num_real_pages));
- real_page_num++)
- result=((real_page[real_page_num]
- =new T[num_elements_per_page]) != NULL);
- if (! result)
- {
- --real_page_num;
- while (real_page_num > 0)
- delete[] real_page[--real_page_num];
- delete[] real_page;
- }
- }
- else
- {
- delete[] starting_element_num;
- delete[] vm_access;
- }
- else
- delete[] vm_access;
- }
- return(result);
- };
-
- template <class T>
- void varray<T>::free_memory()
- // Free real memory used for pages, etc.
- {
- for (int real_page_num=0; real_page_num < num_real_pages; real_page_num++)
- delete[] real_page[real_page_num];
- delete[] real_page;
- delete[] starting_element_num;
- delete[] vm_access;
- return;
- };
-
- template <class T>
- T *varray<T>::vm_ptr(
- long element_num)
- // Return a pointer to an element of the array.
- {
- long earliest_access;
- long expanded_memory_page_num;
- int num_oldest_real_page;
- int page_found;
- int real_page_num;
- T *result;
- long virtual_page_num;
-
- vm_access_num++;
- page_found=FALSE;
- num_oldest_real_page=0;
- earliest_access=vm_access[0];
- for (real_page_num=0;
- ((! page_found) && (real_page_num < num_real_pages));
- real_page_num++)
- if ((element_num >= starting_element_num[real_page_num])
- && (element_num < ((long) num_elements_per_page)
- +(starting_element_num[real_page_num])))
- page_found=TRUE;
- else
- {
- if (vm_access[real_page_num] < earliest_access)
- {
- earliest_access=vm_access[real_page_num];
- num_oldest_real_page=real_page_num;
- }
- }
- if (page_found) // Page is already in real memory.
- {
- real_page_num--;
- result=&(real_page[real_page_num]
- [element_num-starting_element_num[real_page_num]]);
- vm_access[real_page_num]=vm_access_num;
- }
- else // Swap oldest page in real memory for the one sought.
- if (free_expanded_memory)
- {
- virtual_page_num=starting_element_num[num_oldest_real_page]
- /((long) num_elements_per_page);
- expanded_memory_page_num=virtual_page_num;
- expanded_memory_page_num+=expanded_memory_page_num;
- map_expanded_memory(0,expanded_memory_page_num++);
- map_expanded_memory(1,expanded_memory_page_num);
- memcpy((void *) page_frame_ptr,
- (void *) &(real_page[num_oldest_real_page][0]),
- num_elements_per_page*sizeof(T));
- virtual_page_num=element_num/((long) num_elements_per_page);
- expanded_memory_page_num=virtual_page_num;
- expanded_memory_page_num+=expanded_memory_page_num;
- map_expanded_memory(0,expanded_memory_page_num++);
- map_expanded_memory(1,expanded_memory_page_num);
- memcpy((void *) &(real_page[num_oldest_real_page][0]),
- (void *) page_frame_ptr,
- num_elements_per_page*sizeof(T));
- starting_element_num[num_oldest_real_page]
- =virtual_page_num*((long) num_elements_per_page);
- result=&(real_page[num_oldest_real_page][
- element_num-starting_element_num[num_oldest_real_page]]);
- vm_access[num_oldest_real_page]=vm_access_num;
- }
- else
- {
- fseek(vm,
- starting_element_num[num_oldest_real_page]*((long) sizeof(T)),
- SEEK_SET);
- fwrite(&(real_page[num_oldest_real_page][0]),sizeof(T),
- num_elements_per_page,vm);
- starting_element_num[num_oldest_real_page]
- =element_num/((long) num_elements_per_page);
- (starting_element_num[num_oldest_real_page])
- *=((long) num_elements_per_page);
- fseek(vm,
- starting_element_num[num_oldest_real_page]*((long) sizeof(T)),
- SEEK_SET);
- fread(&(real_page[num_oldest_real_page][0]),sizeof(T),
- num_elements_per_page,vm);
- result=&(real_page[num_oldest_real_page][
- element_num-starting_element_num[num_oldest_real_page]]);
- vm_access[num_oldest_real_page]=vm_access_num;
- }
- return result;
- };
-
- template <class T>
- int varray<T>::map_expanded_memory(
- int physical_page,
- long logical_page)
- // Associate a physical page in the physical page frame with a logical page
- // of expanded memory.
- {
- union REGS input_reg;
- union REGS output_reg;
-
- input_reg.h.ah=0x44;
- input_reg.h.al=physical_page;
- input_reg.x.bx=(unsigned int) logical_page;
- input_reg.x.dx=expanded_memory_handle;
- int86(0x67,&input_reg,&output_reg);
- return (output_reg.h.ah == 0);
- }
-
- #endif
-